///////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Filename:		TinyLog.h
//	Author:			Andrew Ciervo
//	Version:		1.0
//	Date Created:	October 30, 2013
//	Date Modified:	November 5, 2013
//	Notes:			Creates a log file for use of debugging, tracing, and general usage.
///////////////////////////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////////
//	Includes
////////////////////////////////////////////////////////////////////////////////////////
#include "TinyLog.h"
#include <sstream>
#include <iomanip>


//=========================================================================
//	Function:	Constructor
//	Params:		
//	Return:		
//	Notes:		Default Constructor
//=========================================================================
TinyLog::TinyLog( void )
{
	fileName = nullptr;
	filePath = nullptr;
}


//=========================================================================
//	Function:	Destructor
//	Params:		
//	Return:		
//	Notes:		Cleans up any memory that is used.
//=========================================================================
TinyLog::~TinyLog( void )
{
	//=========================================================
	// Make sure to clean up the instance.
	//=========================================================
	Uninitialize();
}


//=========================================================================
//	Function:	Initialize
//	Params:		void
//	Return:		void
//	Notes:		Sets up the data members that are used in saving or 
//				loading a file.
//=========================================================================
void TinyLog::Initialize( void )
{
	if( fileName == nullptr )
		fileName = new char[64];

	if( filePath == nullptr )
		filePath = new char[256];
}


//=========================================================================
//	Function:	Uninitialize
//	Params:		void
//	Return:		void
//	Notes:		Cleans up an instance of the class completely.
//=========================================================================
void TinyLog::Uninitialize( void )
{
	CloseFile();

	delete[] fileName;
	delete[] filePath;

	fileName = nullptr;
	filePath = nullptr;
}


//=========================================================================
//	Function:	OpenFile
//	Params:		void
//	Return:		bool
//	Notes:		Safely opens a file.  
//=========================================================================
bool TinyLog::OpenFile( const char* _filePath, const char* _fileName, ios_base::open_mode openMode )
{
	//=========================================================
	// Open the file
	//=========================================================
	fileStream.open( _filePath, openMode );
	
	// Create directory if POSIX for non Windows Operating systems
	//mkdir(P, S_IRWXU|S_IRWXG|S_IRWXO);
	// Windows only operating systems 
	//CreateDirectoryW(P, 0)!= 0
	
	//=========================================================
	// Save the filepath and fileName for later use
	//=========================================================
	if( fileStream.is_open() )
	{
		strcpy_s( fileName, strlen(_fileName)+1, _fileName );
		strcpy_s( filePath, strlen(_filePath)+1, _filePath );
	}

	string header;
	GetLocalSystemTime( header );

	// Actually write to the file
	fileStream << header.c_str()	<< "\t";
	fileStream << "/////////////////////////////////////////////////////////////////////////\n";
	fileStream << header.c_str()	<< "\t";
	fileStream << "//\t\tFile: "		<< fileName << "\n";
	fileStream << header.c_str()	<< "\t";
	fileStream << "/////////////////////////////////////////////////////////////////////////\n";

	//=========================================================
	// Check and return to see if the file has opened
	//=========================================================
	return fileStream.is_open();
}


//=========================================================================
//	Function:	CloseFile
//	Params:		void
//	Return:		bool
//	Notes:		Safely closes the currently open file in the current
//				instance of the class.
//=========================================================================
bool TinyLog::CloseFile( void )
{
	//=========================================================
	// Close the fileStream
	//=========================================================
	if( fileStream.is_open() )
		fileStream.close();

	//=========================================================
	// Check and return to see if the file is still open
	//		- if file is open return negatation of is_open()
	//=========================================================
	return !fileStream.is_open();
}


//=========================================================================
//	Function:	GetLocalSystemTime
//	Params:		string
//	Return:		void
//	Notes:		Gets the local time from the computers system, and returns
//				it through the parameter.  Not multi-platform yet.
//=========================================================================
void TinyLog::GetLocalSystemTime( string&  timeOutput )
{
	// Get the system time
	GetLocalTime( &sysTime );

	// Create header information
	ostringstream	stream;


	// Day
	switch( sysTime.wDayOfWeek )
	{
	case 0: {  stream << "[ Sun"; break; }
	case 1: {  stream << "[ Mon"; break; }
	case 2: {  stream << "[ Tue"; break; }
	case 3: {  stream << "[ Wed"; break; }
	case 4: {  stream << "[ Thu"; break; }
	case 5: {  stream << "[ Fri"; break; }
	case 6: {  stream << "[ Sat"; break; }
	}

	stream << " ";
	
	switch( sysTime.wMonth )
	{
	case 1:  {  stream << "Jan" << " "; break; }
	case 2:  {  stream << "Feb" << " "; break; }
	case 3:  {  stream << "Mar" << " "; break; }
	case 4:  {  stream << "Apr" << " "; break; }
	case 5:  {  stream << "May" << " "; break; }
	case 6:  {  stream << "Jun" << " "; break; }
	case 7:  {  stream << "Jul" << " "; break; }
	case 8:  {  stream << "Aug" << " "; break; }
	case 9:  {  stream << "Sep" << " "; break; }
	case 10: {  stream << "Oct" << " "; break; }
	case 11: {  stream << "Nov" << " "; break; }
	case 12: {  stream << "Dec" << " "; break; }
	}

	// Append the time to the header string
	stream	<< setw(2) << setfill('0') << sysTime.wDay		<< " "
			<< setw(2) << setfill('0') << sysTime.wHour		<< ":"
			<< setw(2) << setfill('0') << sysTime.wMinute	<< ":"
			<< setw(2) << setfill('0') << sysTime.wSecond	<< " " << sysTime.wYear << " ]";

	// Output the header
	timeOutput = stream.str();
}

//=========================================================================
//	Function:	CopyFile
//	Params:		void
//	Return:		bool
//	Notes:		Copies the first file into the second file.
//=========================================================================
bool TinyLog::CopyFiles( const char* firstFileName, const char* secondFileName )
{
	FILE* sourceFile;		
	errno_t err = fopen_s( &sourceFile,"a.txt", "rb");

	if( err != NULL )
		return false;
	
	FILE* destinationFile;	
	err = fopen_s( &destinationFile, "dest/b.txt", "wb");
	
	if( err != NULL )
		return false;

	// Copy the contents of the file
	for( int i = getc(sourceFile); i != EOF; i = getc(sourceFile))
	{
	    putc(i, destinationFile);
	}
	
	fclose(destinationFile);
	fclose(sourceFile);

	// Return Success
	return true;
}

//=========================================================================
//	Function:	WriteFile
//	Params:		void
//	Return:		bool
//	Notes:		Safely write to a file with the function name, function 
//				description, and the result of said function.  
//				Future use might include variadic functions and ... for
//				unlimited use of writing to the file.
//=========================================================================
bool TinyLog::WriteFile( const char* functionName, const char* description, ExitCode code )
{
	if( functionName == nullptr )
		return false;

	if( description == nullptr )
		return false;

	// write to the file
	string header;
	GetLocalSystemTime( header );

	// Actually write to the file
	fileStream << header.c_str()	<< "\t";
	fileStream << code				<< "\t";
	fileStream << functionName		<< "\t";
	fileStream << description		<< "\n";

	// Return success
	return true;
}